/**
 * @file 坐标过滤工具
 * @description 使用布隆过滤器实现高效的坐标去重
 * @author AI Assistant
 * @date 2024-03-09
 */

import { Injectable } from '@nestjs/common';
import { BloomFilter } from 'bloom-filters';
import { LoggerService } from '../../../common/services/logger.service';

@Injectable()
export class CoordinateFilterUtil {
  // 为每个设备维护一个布隆过滤器
  private filters: Map<string, BloomFilter> = new Map();
  // 记录设备最后访问时间，用于清理不活跃设备的过滤器
  private deviceLastAccess: Map<string, number> = new Map();
  // 统计信息
  private stats = {
    totalChecks: 0,
    duplicatesFound: 0,
    devicesTracked: 0
  };

  constructor(private readonly logger: LoggerService) {
    // 定期清理不活跃设备的过滤器
    setInterval(() => this.cleanupInactiveDevices(), 3600000); // 每小时清理一次
  }

  /**
   * 获取设备的布隆过滤器
   * @param deviceId 设备ID
   * @returns 设备对应的布隆过滤器
   */
  private getDeviceFilter(deviceId: string): BloomFilter {
    // 更新设备访问时间
    this.deviceLastAccess.set(deviceId, Date.now());
    
    if (!this.filters.has(deviceId)) {
      // 创建新的布隆过滤器
      // 修改参数：使用BloomFilter.create方法设置合适的过滤器大小和错误率
      // 或者直接使用合适的哈希函数数量而不是错误率
      this.filters.set(deviceId, new BloomFilter(10000, 8)); // 第二个参数改为哈希函数数量8
      this.stats.devicesTracked++;
      this.logger.debug(`为设备 ${deviceId} 创建布隆过滤器`, 'CoordinateFilterUtil');
    }
    
    return this.filters.get(deviceId)!;
  }

  /**
   * 检查坐标是否存在（是否为重复坐标）
   * @param deviceId 设备ID
   * @param lng 经度
   * @param lat 纬度
   * @returns 是否为重复坐标
   */
  public hasCoordinate(deviceId: string, lng: number, lat: number): boolean {
    this.stats.totalChecks++;
    const filter = this.getDeviceFilter(deviceId);
    // 坐标精度保留6位小数，确保匹配精度
    const coordKey = `${lng.toFixed(6)},${lat.toFixed(6)}`;
    const isDuplicate = filter.has(coordKey);
    
    if (isDuplicate) {
      this.stats.duplicatesFound++;
    }
    
    return isDuplicate;
  }

  /**
   * 添加坐标到过滤器
   * @param deviceId 设备ID
   * @param lng 经度
   * @param lat 纬度
   */
  public addCoordinate(deviceId: string, lng: number, lat: number): void {
    const filter = this.getDeviceFilter(deviceId);
    const coordKey = `${lng.toFixed(6)},${lat.toFixed(6)}`;
    filter.add(coordKey);
  }

  /**
   * 清理不活跃设备的过滤器
   * 释放内存，防止内存泄漏
   */
  private cleanupInactiveDevices(): void {
    const now = Date.now();
    let cleanupCount = 0;
    
    for (const [deviceId, lastAccess] of this.deviceLastAccess.entries()) {
      // 清理1小时未访问的设备
      if (now - lastAccess > 3600000) {
        this.filters.delete(deviceId);
        this.deviceLastAccess.delete(deviceId);
        cleanupCount++;
      }
    }
    
    if (cleanupCount > 0) {
      this.logger.log(
        `已清理 ${cleanupCount} 个不活跃设备的坐标过滤器`,
        'CoordinateFilterUtil'
      );
    }
  }

  /**
   * 获取过滤器统计信息
   * @returns 统计信息
   */
  public getStats(): any {
    return {
      ...this.stats,
      duplicateRate: this.stats.totalChecks > 0 
        ? (this.stats.duplicatesFound / this.stats.totalChecks * 100).toFixed(2) + '%' 
        : '0%',
      activeDevices: this.filters.size
    };
  }

  /**
   * 重置设备的过滤器
   * 用于处理新的数据批次
   * @param deviceId 设备ID
   */
  public resetDeviceFilter(deviceId: string): void {
    if (this.filters.has(deviceId)) {
      this.filters.delete(deviceId);
      this.logger.debug(`已重置设备 ${deviceId} 的坐标过滤器`, 'CoordinateFilterUtil');
    }
  }
} 